package com.zmn.oms.zmn.business.impl.clue;

import com.alibaba.fastjson.JSON;
import com.zmn.base.oms.common.model.es.orderwork.EsOrderWork;
import com.zmn.base.oms.common.model.es.orderwork.EsOrderWorkProduct;
import com.zmn.biz.clue.common.consts.MqConst;
import com.zmn.biz.clue.common.enums.ClueSourceTypeEnum;
import com.zmn.biz.clue.common.enums.LowerStatusEnum;
import com.zmn.biz.clue.common.enums.OrderFailReasonEnum;
import com.zmn.biz.clue.common.model.mq.OrderCallbackProductDIO;
import com.zmn.biz.clue.common.model.mq.OrderClueMessageDIO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GateTypeConsts;
import com.zmn.consts.GlobalConsts;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.oms.business.interfaces.es.OrderWorkEsBService;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.enums.EncryptFieldTypeEnum;
import com.zmn.oms.constant.MessageQueueTopicConstant;
import com.zmn.oms.model.dto.order.OrderServiceCompanyQuery;
import com.zmn.oms.services.interfaces.orderencrypt.OrderEncryptService;
import com.zmn.oms.zmn.business.interfaces.clue.OrderClueBService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 类描述
 *
 * @author fubiao
 * @since 2022/09/22
 */
@Service
@Slf4j
public class OrderClueBServiceImpl implements OrderClueBService {

    @Resource
    private ZmnMQSender zmnMQSender;

    @Resource
    private OrderWorkEsBService orderWorkEsBService;

    @Resource
    private OrderEncryptService orderEncryptService;

    private static final Integer PAGE_SIZE = 500;

    @Override
    public void sendOrderOfAutoCaptureToClue(OrderServiceCompanyQuery query, String reason) {
        Integer sourceType = getSourceType(query.getReceiveEntranceId());
        if (Objects.isNull(sourceType)) {
            log.info("无对应的线索来源");
            return;
        }
        OrderClueMessageDIO dio = getMsgDioFromQuery(query);
        dio.setSourceType(sourceType);
        switch (reason) {
            case "无法承接线索":
                dio.setFailReason(OrderFailReasonEnum.NO_RECEIVE.getCode());
                break;
            case "暂无服务商可服务":
                dio.setFailReason(OrderFailReasonEnum.NO_PROVIDER.getCode());
                break;
            case "暂无网格覆盖":
                dio.setFailReason(OrderFailReasonEnum.NO_GRID.getCode());
                break;
            default:
                dio.setFailReason(OrderFailReasonEnum.OTHER.getCode());
                break;
        }
        String message = JSON.toJSONString(dio);
        String key = "biz_clue_" + DateUtil.getNowTimestampMillis();
        log.info("自动抓取线索数据同步给线索系统key:[{}]，message:[{}] 数据源类型:[{}]", key, message, dio.getSourceType());
        zmnMQSender.send(MessageQueueTopicConstant.ZMN_TOPIC_BIZ_CLUE, MqConst.ORDER_CLUE_TAG, key, message);
    }

    @Override
    public void sendOrderOfCronJobToClue() {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                // 工单类型: 新单
                .filter(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_NEW))
                // 工单状态: 已录入
                .filter(QueryBuilders.termQuery("status", OrderStatusConsts.ORDER_STATUS_INPUT))
                // 工单结果状态: 进行中
                .filter(QueryBuilders.termQuery("resultStatus", OrderStatusConsts.WORK_RESULT_DOING));
        // 下单时间7天之后
        Date now = DateUtil.getNow();
        Date startDate = DateUtil.addDays(now, -8);
        Date endDate = DateUtil.addDays(now, -7);
        BoolQueryBuilder timeQuery = QueryBuilders.boolQuery()
                .should(QueryBuilders.rangeQuery("receiveTime").gte(DateUtil.toString(startDate)).lt(DateUtil.toString(endDate)));
        queryBuilder.filter(timeQuery);

        int count = orderWorkEsBService.countByQuery(new NativeSearchQuery(queryBuilder)).intValue();
        if (NumberUtil.isNullOrZero(count)) {
            log.info("没有已录入未确认的单子");
            return;
        }
        log.info("定时任务同步工单系统数据 count={}", count);
        int remainder = 0;
        int limit = 0;
        if (count > 500) {
            remainder = count % 500;
            limit = NumberUtil.isNullOrZero(remainder) ? count / 500 : count / 500 + 1;
        }

        pushOrderWorkToClue(limit, remainder, count, queryBuilder);
    }

    private void pushOrderWorkToClue(int limit, int remainder, int count, BoolQueryBuilder queryBuilder) {
        FetchSourceFilter fetchSourceFilter = new FetchSourceFilter(new String[]{"id", "plat","isTest",
                "contact.phone", "contact.userName", "contact.gender", "contact.address", "contact.streetSource",
                "contact.streetId", "contact.street", "provinceId", "provinceName", "cityId", "cityName", "countyId",
                "countyName", "channelId", "channelName", "productList", "servCategId", "servCategName",
                "productInfo", "dutyTime"}, new String[]{});
        List<EsOrderWork> result = new ArrayList<>(PAGE_SIZE);
        if (NumberUtil.isNullOrZero(limit)) {
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            NativeSearchQuery build = nativeSearchQueryBuilder.withQuery(queryBuilder)
                    .withPageable(PageRequest.of(0, count, Sort.by(Sort.Order.desc("receiveTime"))))
                    .build();
            build.addSourceFilter(fetchSourceFilter);
            List<EsOrderWork> page = orderWorkEsBService.listPageByQuery(build);
            result.addAll(page);
        } else {
            for (int i = 0; i < limit; i++) {
                NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
                NativeSearchQuery build = nativeSearchQueryBuilder.withQuery(queryBuilder)
                        .withPageable(PageRequest.of(i, PAGE_SIZE, Sort.by(Sort.Order.desc("receiveTime"))))
                        .build();
                build.addSourceFilter(fetchSourceFilter);
                List<EsOrderWork> page = orderWorkEsBService.listPageByQuery(build);
                result.addAll(page);
            }
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            NativeSearchQuery build = nativeSearchQueryBuilder.withQuery(queryBuilder)
                    .withPageable(PageRequest.of(limit, remainder, Sort.by(Sort.Order.desc("receiveTime"))))
                    .build();
            build.addSourceFilter(fetchSourceFilter);
            List<EsOrderWork> page = orderWorkEsBService.listPageByQuery(build);
            result.addAll(page);
        }

        // 解密用户电话和地址
        orderEncryptService.batchDecryptEsOrderWork(result, EncryptFieldTypeEnum.USER_TELPHONE, EncryptFieldTypeEnum.USER_ADDRESS);

        result.stream().forEach(esOrderWork -> {
            try {
                OrderClueMessageDIO dio = getMsgDioFromEs(esOrderWork);
                String message = JSON.toJSONString(dio);
                String key = "biz_clue_" + DateUtil.getNowTimestampMillis();
                log.info("定时任务线索数据同步给线索系统key:[{}]，message:[{}]", key, message);
                zmnMQSender.send(MessageQueueTopicConstant.ZMN_TOPIC_BIZ_CLUE, MqConst.ORDER_CLUE_TAG, key, message);
            }catch (Exception e) {
                log.error("定时任务线索数据同步给线索系统出现异常 worKId=[{}]", esOrderWork.getId(), e);
            }
        });
    }

    private OrderClueMessageDIO getMsgDioFromQuery(OrderServiceCompanyQuery query) {
        OrderClueMessageDIO dio = new OrderClueMessageDIO();
        dio.setGrab(GlobalConsts.YES);
        dio.setSourceId(query.getRequestId());
        dio.setLowerStatus(LowerStatusEnum.FAIL.getCode());
        dio.setPlat(query.getPlat());
        dio.setPhone(query.getTelephone());
        dio.setPhone2(query.getTelephone2());
        dio.setPhone3(query.getTelephone3());
        dio.setUserName(query.getUserName());
        dio.setGender(getIntegerValue(query.getGender()));
        dio.setProvinceId(getIntegerValue(query.getProvinceId()));
        dio.setProvinceName(query.getProvinceName());
        dio.setCityId(getIntegerValue(query.getCityId()));
        dio.setCityName(query.getCityName());
        dio.setCountyId(getIntegerValue(query.getCountyId()));
        dio.setCountyName(query.getCountyName());
        dio.setStreetSource(getIntegerValue(query.getStreetSource()));
        dio.setStreetId(getIntegerValue(query.getStreetId()));
        dio.setStreetName(query.getStreet());
        dio.setAddress(query.getAddress());
        dio.setCooperateId(getIntegerValue(query.getChannelId()));
        dio.setCooperateName(query.getChannelName());
        // 判断是否为呼叫录入
        if (StringUtil.isNotBlank(query.getCallId())) {
            dio.setSourceId(query.getCallId());
        }
        return dio;
    }

    private OrderClueMessageDIO getMsgDioFromEs(EsOrderWork esOrderWork) {
        Integer entryMark = esOrderWork.getIsTest() ? GlobalConsts.YES : GlobalConsts.NO;
        OrderClueMessageDIO dio = new OrderClueMessageDIO();
        dio.setGrab(GlobalConsts.NO);
        dio.setEntryMark(entryMark);
        dio.setSourceId(String.valueOf(esOrderWork.getId()));
        dio.setSourceType(ClueSourceTypeEnum.ENTERED_UNCONFIRMED_ORDER.getCode());
        dio.setPlat(esOrderWork.getPlat());
        dio.setPhone(esOrderWork.getContact().getPhone()[0]);
        dio.setUserName(esOrderWork.getContact().getUserName());
        dio.setGender(getIntegerValue(esOrderWork.getContact().getGender()));
        dio.setProvinceId(getIntegerValue(esOrderWork.getProvinceId()));
        dio.setProvinceName(esOrderWork.getProvinceName());
        dio.setCityId(getIntegerValue(esOrderWork.getCityId()));
        dio.setCityName(esOrderWork.getCityName());
        dio.setCountyId(getIntegerValue(esOrderWork.getCountyId()));
        dio.setCountyName(esOrderWork.getCountyName());
        dio.setStreetSource(getIntegerValue(esOrderWork.getContact().getStreetSource()));
        dio.setStreetId(getIntegerValue(esOrderWork.getContact().getStreetId()));
        dio.setStreetName(esOrderWork.getContact().getStreet());
        dio.setAddress(esOrderWork.getContact().getAddress());
        dio.setCooperateId(getIntegerValue(esOrderWork.getChannelId()));
        dio.setCooperateName(esOrderWork.getChannelName());

        List<EsOrderWorkProduct> productList = esOrderWork.getProductList();
        List<OrderCallbackProductDIO> productDIOList = new ArrayList<>(productList.size());
        productList.stream().forEach(product -> {
            OrderCallbackProductDIO productDIO = new OrderCallbackProductDIO();
            productDIO.setServCategId(getIntegerValue(esOrderWork.getServCategId()));
            productDIO.setServCategName(esOrderWork.getServCategName());
            productDIO.setProductInfo(esOrderWork.getProductInfo());
            productDIO.setReserveTime(esOrderWork.getDutyTime());
            productDIO.setBrandId(getIntegerValue(product.getBrandId()));
            productDIO.setProductCount(getIntegerValue(product.getBrandId()));
            if (NumberUtil.isNotNullOrZero(product.getProductId())) {
                productDIO.setProductId(getIntegerValue(product.getBrandId()));
                productDIO.setProductType(GlobalConsts.NO);
                productDIOList.add(productDIO);
                return;
            }
            productDIO.setProductId(getIntegerValue(product.getShowProductId()));
            productDIO.setProductType(GlobalConsts.YES);
            productDIOList.add(productDIO);
        });
        dio.setProductList(productDIOList);
        return dio;
    }

    /**
     *  获取下单来源类型
     * @param receiveEntranceId
     * @return
     */
    private Integer getSourceType(Integer receiveEntranceId) {
        if (Objects.equals(receiveEntranceId, GateTypeConsts.GATE_PLAT_CHAT)) {
            return ClueSourceTypeEnum.QUICK_ORDER.getCode();
        } else if (Objects.equals(receiveEntranceId, GateTypeConsts.GATE_PLAT_BACKSTAGE)) {
            return ClueSourceTypeEnum.ADD_ORDER.getCode();
        } else if (Objects.equals(receiveEntranceId, GateTypeConsts.GATE_PLAT_CC)) {
            return ClueSourceTypeEnum.CALL.getCode();
        }
        return null;
    }

    private Integer getIntegerValue(Integer integer) {
        return NumberUtil.isNotNullOrZero(integer) ? integer : null;
    }
}
